package com.ck.transaction.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ck.common.entity.SysUser;
import com.ck.transaction.mapper.SysUserMapper;
import com.ck.transaction.service.SpringTransactionDemoService2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;



@Service
@Slf4j
public class SpringTransactionDemoService {
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SpringTransactionDemoService springTransactionDemoService;
    @Autowired
    private SpringTransactionDemoService2 springTransactionDemoService2;

    /**
     *
     * 加入事务、不调用其他方法（事务生效）
     */
    @Transactional
    public void addSysUserEntityToDB1(){
        SysUser user = getSysUserEntity(1);
        sysUserMapper.insert(user);
    }

    /**
     *
     * 不加入事务、最后抛出【运行时异常】（出现异常 不会 回滚）
     */
    public void addSysUserEntityToDB2(){
        SysUser user = getSysUserEntity(2);
        this.sysUserMapper.insert(user);
        int i = 1 / 0;
    }

    /**
     *
     * 加入事务、最后抛出【运行时异常】（事务生效：出现异常 会 回滚）
     */
    @Transactional
    public void addSysUserEntityToDB3(){
        SysUser user = getSysUserEntity(3);
        this.sysUserMapper.insert(user);
        int i = 1 / 0;
    }

    /**
     *
     * 【事务失效场景1 ： 异常被try catch吞掉】
     * 加入事务、最后抛出【运行时异常】、自行try catch（事务失效1：异常会被try catch吞掉，不会进行回滚）
     */
    @Transactional
    public void addSysUserEntityToDB4(){
        try {
            SysUser user = getSysUserEntity(4);
            this.sysUserMapper.insert(user);
            int i = 1 / 0;
        }catch (Exception e){
            log.error("保存用户信息出错：{}",e);
        }
    }

    /**
     *
     * 【事务失效场景2：抛出的是检查型异常】
     * 加入事务、最后抛出【检查型异常】（事务失效2：出现异常不会回滚）
     * 注意：手动指定rollback = ParseException.class后会进行回滚
     */
    @Transactional //(rollbackFor = {ParseException.class})
    public void addSysUserEntityToDB5() throws ParseException {
        SysUser user = getSysUserEntity(5);
        sysUserMapper.insert(user);
        new SimpleDateFormat("yyyy-MM-dd").parse("123123");
    }

    /**
     *
     * 加入事务、最后抛出【检查型异常】, 手动指定rollback = ParseException.class后会进行回滚
     */
    @Transactional(rollbackFor = {ParseException.class})
    public void addSysUserEntityToDB6() throws ParseException {
        SysUser user = getSysUserEntity(6);
        sysUserMapper.insert(user);
        new SimpleDateFormat("yyyy-MM-dd").parse("123123");
    }

    /**
     *
     * 加入事务、最后抛出【检查型异常】、自行try catch（事务失效：出现异常不会回滚）
     */
    @Transactional(rollbackFor = {ParseException.class})
    public void addSysUserEntityToDB7(){
        try {
            SysUser user = getSysUserEntity(7);
            sysUserMapper.insert(user);
            new SimpleDateFormat("yyyy-MM-dd").parse("123123");
        }catch (Exception e){
            log.error("保存用户信息出错：{}",e);
        }
    }

    /**
     *
     * 【事务失效场景3：本类无事务方法调用本类有事务方法】
     * 当前方法无事务，使用this调用当前类的事务方法（事务失效3：事务方法中出现异常不会回滚）
     * 原理：发生自调用，类里面使用this调用本类的方法，此时这个this不是代理对象，所以事务失效
     */
    public void addSysUserEntityToDB8(){
        this.addSysUserEntityToDB3();
    }

    /**
     *
     * 当前方法无事务，使用spring容器中对象引用调用当前类的事务方法（事务生效：事务方法中出现异常会回滚）
     * 原理：发生自调用，类里面使用容器中的代理类调用的事务方法，所以事务生效
     */
    public void addSysUserEntityToDB9(){
        springTransactionDemoService.addSysUserEntityToDB3();
    }


    /**
     *
     * 当前方法无事务，调用其他类的事务方法（事务生效：事务方法中出现异常会回滚）
     * 原理：发生自调用，类里面使用容器中其他类的代理对象调用的事务方法，所以事务生效
     * 代理对象:  springTransactionDemoService2
     */
    public void addSysUserEntityToDB10(){
        springTransactionDemoService2.addSysUserEntityToDB10();
    }

    /**
     *
     * 当前类有事务方法调用当前类的事务方法（事务生效，下游的事务方法中出现异常会进行全面回滚）
     */
    @Transactional
    public void addSysUserEntityToDB11(){
        SysUser user = getSysUserEntity(11);
        this.sysUserMapper.insert(user);
        addSysUserEntityToDB3();
    }

    /**
     *
     * 【事务失效场景4：事务方法被非public修饰】
     */
    @Transactional
     void addSysUserEntityToDB12(){
        SysUser user = getSysUserEntity(12);
        this.sysUserMapper.insert(user);
        int i = 1 / 0;
    }

    /**
     *
     * 【事务失效场景5：事务方法被final修饰】
     *  被final修饰的方法，代理类中是获取不到成员属性的(this.sysUserMapper)，所以事务失效
     */
    @Transactional
    public final void addSysUserEntityToDB13(){
        SysUser user = getSysUserEntity(13);
        this.sysUserMapper.insert(user);
    }

    /**
     *
     * 【事务失效场景6：设置了错误的传播行为】
     * Propagation.NOT_SUPPORTED表示当前方法不应该在一个事务内执行。
     * 当方法被调用时，如果存在活动的事务，它将被挂起，该方法将在没有事务的环境中执行。
     * 通常用于需要在非事务环境中执行的方法
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void addSysUserEntityToDB14(){
        SysUser user = getSysUserEntity(14);
        this.sysUserMapper.insert(user);
        addSysUserEntityToDB1();
        int i = 1 / 0;
    }

    @Transactional
    public String add88SysUserEntityToDB() {
        List<SysUser> users = this.sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserName, "测试用户88"));
        if(CollectionUtil.isEmpty(users)){
            SysUser user = getSysUserEntity(88);
            user.setUserName("测试用户"+88);
            this.sysUserMapper.insert(user);
            return "添加用户88成功";
        }
        return "数据库已存在88用户，无需添加";
    }



    public static SysUser getSysUserEntity(Integer num) {
        SysUser user = new SysUser();
        user.setUserName("事务测试用户" + num);
        user.setPassword("密码" + num );
        user.setSex("男");
        user.setPhonenumber("17758999271");
        return user;
    }
}
